package com.micro.service.impl;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.micro.controller.request.AddHotelRequest;
import com.micro.controller.request.HotelBookingRequest;
import com.micro.dto.HotelDTO;
import com.micro.dto.HotelOrderDTO;
import com.micro.dto.UserInfoDTO;
import com.micro.dto.UserProfileDTO;
import com.micro.entity.Hotel;
import com.micro.entity.HotelOrder;
import com.micro.entity.HotelOrder.OrderStatus;
import com.micro.feign.UserServiceFeign;
import com.micro.repository.HotelOrderRepository;
import com.micro.repository.HotelRepository;
import com.micro.service.HotelService;

@Service
public class HotelServiceImpl implements HotelService {

    private static final Logger logger = LoggerFactory.getLogger(HotelServiceImpl.class);

    @Autowired
    private HotelRepository hotelRepository;

    @Autowired
    private HotelOrderRepository hotelOrderRepository;


    private final UserServiceFeign userServiceFeign;
    public HotelServiceImpl(HotelRepository hotelRepository,
                            HotelOrderRepository hotelOrderRepository,
                            UserServiceFeign userServiceFeign) {
        this.hotelRepository = hotelRepository;
        this.hotelOrderRepository = hotelOrderRepository;
        this.userServiceFeign = userServiceFeign;
    }
    private String getUsernameByUserId(Long userId) {
        UserProfileDTO profile = userServiceFeign.getUserProfile(userId);
        return profile.getRealName();
    }

    // TODO: 后续通过微服务调用 User Service
    // @Autowired
    // private UserService userService;

    @Override
    @Transactional(readOnly = true) // 只读事务
    public List<HotelDTO> searchHotelsByCity(String city) {
        try {
            logger.info("服务层开始搜索酒店，城市参数: '{}'", city);
            List<Hotel> hotels = hotelRepository.findByCityName(city);
            logger.info("MyBatis查询返回 {} 个酒店", hotels.size());
            if (!hotels.isEmpty()) {
                logger.info("找到酒店: {}", hotels.get(0).getHotelName());
            }
            return hotels.stream()
                    .map(HotelDTO::new) // 将 Hotel 实体转换为 HotelDTO
                    .collect(Collectors.toList());
        } catch (Exception e) {
            logger.error("搜索酒店时发生异常: " + e.getMessage(), e);
            throw new RuntimeException("搜索酒店时发生异常: " + e.getMessage(), e);
        }
    }

    @Override
    @Transactional(readOnly = true) // 只读事务
    public List<HotelDTO> searchHotelByNameAndCity(String hotelName, String city) {
        try {
            logger.info("服务层开始搜索酒店详情，酒店名称: '{}', 城市: '{}'", hotelName, city);
            List<Hotel> hotels = hotelRepository.findByCityNameAndHotelNameContaining(city, hotelName);
            logger.info("MyBatis查询返回 {} 个酒店", hotels.size());
            if (!hotels.isEmpty()) {
                logger.info("找到酒店: {}", hotels.get(0).getHotelName());
            }
            // 将查询结果（Hotel 实体列表）转换为 HotelDTO 列表
            return hotels.stream()
                    .map(HotelDTO::new) // 将 Hotel 实体转换为 HotelDTO
                    .collect(Collectors.toList());
        } catch (Exception e) {
            logger.error("搜索酒店详情时发生异常: " + e.getMessage(), e);
            throw new RuntimeException("搜索酒店详情时发生异常: " + e.getMessage(), e);
        }
    }

    @Override
    @Transactional(readOnly = true) // 只读事务
    public Hotel getHotelById(Long hotelId) {
        try {
            logger.info("根据酒店ID获取酒店信息，酒店ID: {}", hotelId);
            Hotel hotel = hotelRepository.findHotelByHotelId(hotelId);
            if (hotel != null) {
                logger.info("找到酒店: {}", hotel.getHotelName());
            } else {
                logger.info("未找到酒店，ID: {}", hotelId);
            }
            return hotel;
        } catch (Exception e) {
            logger.error("根据酒店ID获取酒店信息时发生异常: " + e.getMessage(), e);
            throw new RuntimeException("根据酒店ID获取酒店信息时发生异常: " + e.getMessage(), e);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class) // 发生任何异常都回滚事务
    public HotelOrder bookHotel(HotelBookingRequest request) {
        // 1. 验证用户和酒店是否存在
        //userService.getUserProfile(request.getUserId()); // 如果用户未找到则抛出异常
        Hotel hotel = hotelRepository.findHotelByHotelId(request.getHotelId());
        if (hotel == null) {
            throw new RuntimeException("未找到酒店，ID: " + request.getHotelId());
        }

        // 2. 检查房间可用性（基于 remainingRooms 的简化实现）
        if (hotel.getRemainingRooms() <= 0) {
            throw new RuntimeException("该酒店没有可用房间。");
        }
        // 注意：实际系统中需要更复杂的可用性检查，基于日期和房间类型。
        try {
            BigDecimal amount = request.getPaymentAmount();
            String username = getUsernameByUserId(request.getUserId());
            userServiceFeign.deductBalance(request.getUserId(), amount);
        } catch (Exception e) {
            throw new RuntimeException("用户余额扣款失败：" + e.getMessage());
        }
        // 4. 创建订单
        HotelOrder order = new HotelOrder();
        order.setUserId(request.getUserId());
        order.setHotelId(request.getHotelId());
        order.setCheckInDate(request.getCheckInDate());
        order.setCheckOutDate(request.getCheckOutDate());
        order.setOrderStatus(OrderStatus.BOOKED); // 设置订单状态为已预订
        order.setPaymentAmount(request.getPaymentAmount());
        order.setPaymentMethod(request.getPaymentMethod());
        order.setPaymentTime(LocalDateTime.now()); // 设置支付时间
        order.setUpdateTime(LocalDateTime.now()); // 设置更新时间
        // 设置过期时间（例如，入住日期之前或固定期限）
        order.setExpireTime(request.getCheckInDate().atStartOfDay()); // 示例：在入住日期的开始时过期

        hotelOrderRepository.insert(order); // 保存订单

        // 5. 减少剩余房间数（简化实现）
        hotel.setRemainingRooms(hotel.getRemainingRooms() - 1);
        hotelRepository.updateById(hotel); // 更新酒店信息

        return order;
    }

    @Override
    @Transactional(rollbackFor = Exception.class) // 发生任何异常都回滚事务
    public boolean cancelBooking(Long orderId) {

        HotelOrder order = hotelOrderRepository.findByOrderId(orderId);

        if (order == null) {
            throw new RuntimeException("未找到订单或订单不属于该用户。");
        }

        // 检查订单是否可以取消（例如，未入住或未退款）
        if (order.getOrderStatus() != OrderStatus.BOOKED) {
            throw new RuntimeException("订单当前状态无法取消: " + order.getOrderStatus());
        }

        // 检查是否允许取消（例如，在入住日期之前）
        if (LocalDateTime.now().isAfter(order.getCheckInDate().atStartOfDay())) {
            throw new RuntimeException("入住日期后不允许取消。");
        }

        Long userId = order.getUserId();
        // 1. 退款给用户（为简化起见，假设全额退款）
        // TODO: 通过微服务调用退款到用户余额
        System.out.println("退款处理 - 等待用户服务接口就绪");

        // 2. 更新订单状态
        System.out.println("已退票");
        order.setOrderStatus(OrderStatus.REFUNDED); // 设置订单状态为已退款
        order.setRefundAmount(order.getPaymentAmount()); // 设置退款金额
        order.setRefundTime(LocalDateTime.now()); // 设置退款时间
        order.setUpdateTime(LocalDateTime.now()); // 更新时间
        hotelOrderRepository.updateById(order); // 保存更新后的订单

        // 3. 增加剩余房间数（简化实现）
        Hotel hotel = hotelRepository.selectById(order.getHotelId());
        if (hotel == null) {
            throw new RuntimeException("未找到订单对应的酒店，订单ID: " + order.getHotelId());
        }
        hotel.setRemainingRooms(hotel.getRemainingRooms() + 1);
        hotelRepository.updateById(hotel); // 更新酒店信息

        return true;
    }

    @Override
    @Transactional(readOnly = true) // 只读事务
    public List<HotelOrderDTO> getUserBookingHistory(Long userId) {
        // TODO: 通过微服务调用验证用户是否存在
        // 临时跳过用户验证，等待用户服务接口就绪

        List<HotelOrder> orders = hotelOrderRepository.findByUserIdOrderByUpdateTimeDesc(userId); // 查询用户订单历史

        return orders.stream().map(order -> {
            HotelOrderDTO dto = new HotelOrderDTO(order);
            // 获取酒店名称并包含在 DTO 中
            Hotel hotel = hotelRepository.selectById(order.getHotelId());
            if (hotel != null) {
                dto.setHotelName(hotel.getHotelName());
            }
            return dto;
        }).collect(Collectors.toList()); // 将 HotelOrder 实体列表转换为 HotelOrderDTO 列表
    }

    /**
     * 添加新的酒店。
     * @param request 添加酒店的请求详情。
     * @return 创建的 Hotel 实体。
     */
    @Override
    @Transactional // 写事务
    public Hotel addHotel(AddHotelRequest request) {
        // 创建新的 Hotel 实体
        Hotel hotel = new Hotel();
        hotel.setHotelName(request.getHotelName());
        hotel.setHotelAddress(request.getHotelAddress());
        hotel.setHotelRating(request.getHotelRating());
        hotel.setRemainingRooms(request.getRemainingRooms());
        hotel.setHotelDetail(request.getHotelDetail());
        hotel.setPrice(request.getPrice());

        // 保存酒店实体
        hotelRepository.insert(hotel);

        return hotel;
    }
}